package com.chuan.icons;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.R.integer;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.Contacts;
import android.provider.Contacts.People;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

public class FriendActivity extends ListActivity {
	public String mUser = null;
	public String mSite = null;
	public JSONObject mParameter = null;

	private JSONArray mFriends = null;
	private int mFriendType = -1;
	private Menu mMenu;

	private SiteBase mSiteObj = null;
	private FriendAdapter mFriendAdapter = null;

	private final int ACTION_PAIRED_FRIENDS = 101;
	private final int ACTION_UPDATE_FRIENDS = 102;
	private final int ACTION_CLEAN_FRIENDS = 103;
	private final int ACTION_SET_PHOTO = 104;
	private final int ACTION_UPDATE_ICON = 105;
	private final int ACTION_GET_FRIENDS = 106;

	public static final int REFRESH_FRIENDS = 200;
	public static final int DOWNLOAD_COMPLETE = 201;
	public static final int DOWNLOAD_START = 202;
	public static final int UPDATE_FRIEND = 202;

	public static final int PICK_CONTACT = 301;

	public static final int UPDATE_DIALOG_INFO = 401;
	public static final int CLOSE_DIALOG = 402;

	// Selected friends item id.
	private String mSelectedFID = null;

	// Downloader, use a thread for this.
	private Thread mDownloadThread = null;
	public Handler mDownloadHandler = null;

	// Info dialog
	private ProgressDialog mDialog = null;

	public Boolean mNeedRefresh = false;

	public Handler mMainHandler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case REFRESH_FRIENDS:
				refreshList();
				break;
			case DOWNLOAD_COMPLETE:
				refreshItem(msg.getData().getInt("position"));
				break;
			case UPDATE_FRIEND:
				refreshItem(msg.getData().getInt("position"));
				break;

			case UPDATE_DIALOG_INFO:
				String message = null;
				if (msg.getData().containsKey("msg")) {
					message = msg.getData().getString("msg");
				}
				setDialogInfo(message);
				break;
			case CLOSE_DIALOG:
				Boolean delay = msg.getData().getBoolean("delay");
				if (mDialog != null && mDialog.isShowing()) {
					if (delay) {
						final Thread delay_thread = new Thread() {
							@Override
							public void run() {
								try {
									Thread.sleep(1000);
								} catch (InterruptedException e) {
								}
								sendCloseDialogMsg(false);
							}
						};
						delay_thread.start();
					} else {
						mDialog.dismiss();
					}
				}
				break;
			}
			super.handleMessage(msg);
		}
	};

	private void setDialogInfo(String msg) {
		if (mDialog == null || !mDialog.isShowing()) {
			return;
		}

		if (msg != null && msg.length() > 0) {
			mDialog.setMessage(msg);
		}
	}

	public void sendSetDialogMsg(String msg) {
		if (msg == null) {
			return;
		}

		Message sent_msg = new Message();
		sent_msg.what = UPDATE_DIALOG_INFO;
		Bundle b = new Bundle();
		b.putString("msg", msg);
		sent_msg.setData(b);
		mMainHandler.sendMessage(sent_msg);
	}

	public void sendCloseDialogMsg(Boolean delay) {
		Message sent_msg = new Message();
		sent_msg.what = CLOSE_DIALOG;
		Bundle b = new Bundle();
		b.putBoolean("delay", delay);
		sent_msg.setData(b);
		mMainHandler.sendMessage(sent_msg);
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.friend);

		mNeedRefresh = false;

		Intent it = getIntent();
		mUser = it.getStringExtra(Constants.PARAMETER_USER);
		mSite = it.getStringExtra(Constants.PARAMETER_SITE);
		try {
			mParameter = LiteDB.getAccountDetail(mUser, mSite).getJSONObject(
					"parameter");
		} catch (JSONException e) {
			Log.e(Constants.LOG_FLAG, "Can not get account parameter.");
			finish();
		}

		mFriendType = it.getIntExtra(Constants.PARAMETER_TYPE, -1);

		// 将自己的 MSG Handler加入到全局表中
		FriendsTab.mActivityDict.put(mFriendType, this);

		mFriends = new JSONArray();
		if (mUser == null || mSite == null || mFriendType == -1) {
			finish();
		}

		mSiteObj = SiteBase.getSiteClass(mSite, this);
		if (mSiteObj == null) {
			finish();
		}

		startSyncAction(ACTION_GET_FRIENDS, true);

		if (mDownloadThread == null || !mDownloadThread.isAlive()) {
			mDownloadThread = new Downloader();
			mDownloadThread.start();
		}

		mFriendAdapter = new FriendAdapter(this);
		setListAdapter(mFriendAdapter);
	}

	private void refreshSpecifyActivity(int friend_type) {
		if (!FriendsTab.mActivityDict.containsKey(friend_type)) {
			return;
		}

		FriendsTab.mActivityDict.get(friend_type).mNeedRefresh = true;
	}

	private void refreshAllActivity() {
		refreshSpecifyActivity(Constants.PAIRED_TYPE);
		refreshSpecifyActivity(Constants.GUESS_TYPE);
		refreshSpecifyActivity(Constants.UNKNOWN_TYPE);
	}

	public void refreshList() {
		updateShowFriends();
		mFriendAdapter.notifyDataSetChanged();

		mNeedRefresh = false;
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		mMenu = menu;
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.friends, mMenu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.PairFriends:
			startSyncAction(ACTION_PAIRED_FRIENDS, true);
			return true;
		case R.id.Update:
			startSyncAction(ACTION_UPDATE_FRIENDS, true);
			return true;
		case R.id.Clean:
			startSyncAction(ACTION_CLEAN_FRIENDS, true);
			return true;
		default:
			break;
		}

		return false;
	}

	@Override
	protected void onResume() {
		super.onResume();
		if (mNeedRefresh) {
			mNeedRefresh = false;
			refreshList();
		}
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
	}

	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		// 如果是第三个 Activity，即没有找到能够匹配的联系人，那么弹出不同的菜单。
		if (mFriendType == Constants.UNKNOWN_TYPE) {
			unknwonUserAction(position).show();
		} else {
			pairedUserAction(position).show();
		}
	}

	public void showInfo(String info) {
		Toast.makeText(this, info, Toast.LENGTH_SHORT).show();
	}

	private void sendRefreshListMsg() {
		Message msg = new Message();
		msg.what = REFRESH_FRIENDS;
		mMainHandler.sendMessage(msg);
	}

	private void startSyncAction(final int action, Boolean indeterminate) {
		mDialog = new ProgressDialog(this);
		mDialog.setTitle("");
		mDialog.setMessage("");
		mDialog.setIndeterminate(indeterminate);

		final Thread sync_thread = new Thread() {
			@Override
			public void run() {
				Boolean delay = true;
				try {
					switch (action) {
					case ACTION_PAIRED_FRIENDS:
						if (pairFriends(mUser, mSite)) {
							refreshAllActivity();
							sendRefreshListMsg();
						}
						break;
					case ACTION_UPDATE_FRIENDS:
						if (updateFriendsList(mUser, mSite)) {
							refreshAllActivity();
							sendRefreshListMsg();
						}
						break;
					case ACTION_CLEAN_FRIENDS:
						cleanFriendsList(mUser, mSite);
						sendRefreshListMsg();
						break;
					case ACTION_SET_PHOTO:
						break;
					case ACTION_UPDATE_ICON:
						break;
					case ACTION_GET_FRIENDS:
						delay = false;
						if (initFriends()) {
							refreshAllActivity();
							sendRefreshListMsg();
						}
						break;
					default:
						break;
					}
					setResult(RESULT_OK);
				} catch (Exception e) {
					Log.e(Constants.LOG_FLAG, "Sync action fail.", e);
					setResult(RESULT_CANCELED);
				} finally {
					sendCloseDialogMsg(delay);
				}
			}
		};

		mDialog.setOnCancelListener(new OnCancelListener() {
			@Override
			public void onCancel(DialogInterface dialog) {
				sync_thread.interrupt();
			}
		});

		sync_thread.start();
		mDialog.show();
	}

	// Refresh listview item manually.
	private void refreshItem(int position) {
		ListView self_view = this.getListView();
		RelativeLayout view = null;
		ViewHolder holder = null;

		for (int i = 0; i < self_view.getChildCount(); ++i) {
			view = (RelativeLayout) self_view.getChildAt(i);
			if (view == null) {
				break;
			}

			holder = (ViewHolder) view.getTag();
			if (holder.position == position) {
				mFriendAdapter.showIconItem(holder, position);
				break;
			}
		}
	}

	public void sentDownloadMsg(String icon_url, int position) {
		Message sent_msg = new Message();
		sent_msg.what = DOWNLOAD_START;
		Bundle b = new Bundle();
		b.putString("url", icon_url);
		b.putInt("position", position);
		sent_msg.setData(b);
		mDownloadHandler.sendMessage(sent_msg);
	}

	private class FriendAdapter extends BaseAdapter {
		private LayoutInflater mInflater;

		public FriendAdapter(Context context) {
			mInflater = LayoutInflater.from(context);
		}

		public int getCount() {
			return mFriends.length();
		}

		public Object getItem(int position) {
			return position;
		}

		public long getItemId(int position) {
			return position;
		}

		public Bitmap getIcons(String url) {
			byte[] pic_data = null;
			pic_data = LiteDB.get_pic(url);

			if (pic_data == null) {
				return null;
			}
			return BitmapFactory.decodeByteArray(pic_data, 0, pic_data.length);
		}

		public void showIconItem(ViewHolder holder, int position) {
			String name = null, contact_name = null;
			int contact_id = -1;
			String icon_url = null;
			try {
				name = mFriends.getJSONObject(position).getJSONObject(
						"parameter").getString("name");
				icon_url = mFriends.getJSONObject(position).getJSONObject(
						"parameter").getString("icon");
				contact_id = mFriends.getJSONObject(position).getInt("c_id");
			} catch (JSONException e) {
				return;
			}

			holder.friend_name.setText(name);
			holder.contact_name.setText(null);

			Bitmap icon = getIcons(icon_url);
			if (icon == null) {
				holder.friend_icon.setVisibility(View.INVISIBLE);
				holder.wait_bar.setVisibility(View.VISIBLE);

				// Try to Download pic.
				sentDownloadMsg(icon_url, position);
			} else {
				holder.friend_icon.setImageBitmap(icon);
				holder.friend_icon.setVisibility(View.VISIBLE);
				holder.wait_bar.setVisibility(View.INVISIBLE);
			}

			if (contact_id < 0) {
				return;
			}

			contact_name = Common.getContactNameByID(contact_id);
			if (contact_name != null) {
				holder.contact_name.setText(contact_name);
			}

			if (Common.mContactsPhoto.containsKey(contact_id)) {
				holder.contact_icon.setImageBitmap(Common.mContactsPhoto
						.get(contact_id));
			} else {
				Bitmap photo = getContactPhoto(contact_id);
				Common.mContactsPhoto.put(contact_id, photo);
				holder.contact_icon.setImageBitmap(photo);
			}
		}

		public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder holder;

			if (convertView == null) {
				convertView = mInflater.inflate(R.layout.friend_item, null);

				holder = new ViewHolder();
				holder.friend_name = (TextView) convertView
						.findViewById(R.id.RenrenName);
				holder.friend_icon = (ImageView) convertView
						.findViewById(R.id.RenrenHeadImage);
				holder.contact_name = (TextView) convertView
						.findViewById(R.id.ContactName);
				holder.contact_icon = (ImageView) convertView
						.findViewById(R.id.ContactHeadImage);
				holder.wait_bar = (ProgressBar) convertView
						.findViewById(R.id.WaitBar);
				convertView.setTag(holder);
			} else {
				holder = (ViewHolder) convertView.getTag();
				holder.friend_icon.setImageBitmap(null);
				holder.contact_icon.setImageBitmap(null);
			}

			holder.position = position;

			showIconItem(holder, position);

			return convertView;
		}
	}

	public Bitmap getContactPhoto(int contact_id) {
		Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI,
				contact_id);
		return People.loadContactPhoto(this, personUri, 0, null);
	}

	public static class ViewHolder {
		ProgressBar wait_bar;
		TextView friend_name;
		TextView contact_name;
		ImageView friend_icon;
		ImageView contact_icon;

		int position;
	}

	public void refreshPhoto(int position) {
		// Delete photo in db, and then try to refresh it.
		String url = null;
		try {
			url = mFriends.getJSONObject(position).getJSONObject("parameter")
					.getString("icon");
			LiteDB.delete_pic(url);
			sentDownloadMsg(url, position);
			refreshItem(position);
		} catch (JSONException e) {
			Log.e(Constants.LOG_FLAG, "Delete pic fail.");
		}
	}

	private void sendUpdateFriendMsg(int position) {
		Message sent_msg = new Message();
		sent_msg.what = UPDATE_FRIEND;
		Bundle b = new Bundle();
		b.putInt("position", position);
		sent_msg.setData(b);
		mMainHandler.sendMessage(sent_msg);
	}

	public void setPhoto(int position) {
		JSONObject obj;
		int contact_id = -1;
		String url = null;
		try {
			obj = mFriends.getJSONObject(position);
			contact_id = obj.getInt("c_id");
			url = obj.getJSONObject("parameter").getString("icon");
		} catch (JSONException e) {
		}
		if (contact_id == -1) {
			return;
		}

		Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI,
				contact_id);

		byte[] pic_data = LiteDB.get_pic(url);
		if (pic_data != null) {
			People.setPhotoData(getContentResolver(), personUri, pic_data);
			Common.mContactsPhoto.put(contact_id, BitmapFactory
					.decodeByteArray(pic_data, 0, pic_data.length));

			// Update friends list item.
			sendUpdateFriendMsg(position);
		}
	}

	public void setContactName(int position) {
		JSONObject obj;
		int contact_id = -1;
		String name = null;
		try {
			obj = mFriends.getJSONObject(position);
			contact_id = obj.getInt("c_id");
			name = obj.getJSONObject("parameter").getString("name");
		} catch (JSONException e) {
		}

		if (contact_id == -1) {
			return;
		}

		// showInfo(name
		// + " -> "
		// + Common.mContactsDict.getJSONObject(
		// Integer.toString(contact_id)).getString("name"));

		Uri contactUri = ContentUris.withAppendedId(People.CONTENT_URI,
				contact_id);
		ContentValues values = new ContentValues();
		values.put(Contacts.People.NAME, name);
		
		// TODO: 应该先读出信息！改掉。
		values.put(Contacts.People.STARRED, 0);
		if (getContentResolver().update(contactUri, values, null, null) > 0) {
			Common.updateContactName(contact_id, name);

			// Update friends list item.
			sendUpdateFriendMsg(position);
		}
	}

	private Dialog pairedUserAction(final int position) {
		AlertDialog.Builder b = new AlertDialog.Builder(this);
		b.setTitle(R.string.str_selectaction);
		b.setItems(R.array.Actions, new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				if (which == 0) {
					// Refresh.
					refreshPhoto(position);
				} else if (which == 1) {
					// Set as icons.
					setPhoto(position);
				} else if (which == 2) {
					// Set contact name.
					setContactName(position);
				} else if (which == 3) {
					deleteFriendItem(position);
				}
			}
		});
		return b.create();
	}

	private Dialog unknwonUserAction(final int position) {
		AlertDialog.Builder b = new AlertDialog.Builder(this);
		b.setTitle(R.string.str_selectaction);
		b.setItems(R.array.UnknownActions,
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						if (which == 0) {
							// Refresh.
							refreshPhoto(position);
						} else if (which == 1) {
							// Delete.
							deleteFriendItem(position);
						} else if (which == 2) {
							// Select paired contact manually.
							try {
								mSelectedFID = mFriends.getJSONObject(position)
										.getString("f_id");
							} catch (JSONException e) {
								return;
							}
							Intent intent = new Intent(Intent.ACTION_PICK,
									People.CONTENT_URI);
							startActivityForResult(intent, PICK_CONTACT);
						}
					}
				});
		return b.create();
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (requestCode == PICK_CONTACT) {
			// 手工指定配对的联系人头像
			if (resultCode == Activity.RESULT_OK) {
				Uri contactData = data.getData();
				Cursor c = managedQuery(contactData, null, null, null, null);
				if (c.moveToFirst()) {
					int c_id = c.getInt(c.getColumnIndexOrThrow(People._ID));
					addPairedRelationship(c_id, mSelectedFID);
					deleteRelationship(-1, mSelectedFID, Constants.UNKNOWN_TYPE);
					sendRefreshListMsg();

					// 设置Paired Activity 状态，以便用户下次点击该 Activity
					// 的时候能够刷新一下，显示出当前添加的这个好友头像。
					refreshSpecifyActivity(Constants.PAIRED_TYPE);
				}
				c.close();
			}
		}
	}

	private void addPairedRelationship(int c_id, String f_id) {
		LiteDB.addRelationship(mUser, mSite, f_id, c_id, Constants.PAIRED_TYPE);
	}

	private void addUnknownRelationship(String f_id) {
		LiteDB.addRelationship(mUser, mSite, f_id, -1, Constants.UNKNOWN_TYPE);
	}

	private void deleteRelationship(int c_id, String f_id, int relationship) {
		LiteDB
				.deleteSpecifyRelationship(mUser, mSite, f_id, c_id,
						relationship);
	}

	private Boolean deleteFriendItem(int position) {
		JSONObject fdata;
		try {
			fdata = mFriends.getJSONObject(position);
			deleteRelationship(fdata.getInt("c_id"), fdata.getString("f_id"),
					mFriendType);

			// 如果是从Paired 和 Guess 删除，那么把这个好友加到 unknown 里面去
			if (mFriendType == Constants.PAIRED_TYPE
					|| mFriendType == Constants.GUESS_TYPE) {
				// 然后刷新 Unknown Activity
				addUnknownRelationship(fdata.getString("f_id"));
				refreshSpecifyActivity(Constants.UNKNOWN_TYPE);

				sendRefreshListMsg();
				return true;
			}

			sendRefreshListMsg();
		} catch (JSONException e) {
			return false;
		}

		return true;
	}

	private Boolean initFriends() {
		sendSetDialogMsg(getResources().getString(R.string.str_read_friends));
		long friends_count = LiteDB.getFriendsCount(mUser, mSite);
		if (friends_count < 1) {
			sendSetDialogMsg(getResources().getString(
					R.string.str_read_friends_fail));
			if (getFriendsList() == true) {
				return pairFriends(mUser, mSite);
			} else {
				return false;
			}
		}

		sendSetDialogMsg(getResources().getString(R.string.str_show_friends));
		if (!updateShowFriends()) {
			sendSetDialogMsg(getResources().getString(
					R.string.str_show_friends_fail));
			return false;
		}

		return true;
	}

	/* Get friends from DB. */
	private Boolean updateShowFriends() {
		mFriends = LiteDB.getPairedFriends(mUser, mSite, mFriendType);
		if (mFriends.length() < 1) {
			return false;
		}
		return true;
	}

	private Boolean pairFriends(String user, String site) {
		sendSetDialogMsg(getResources().getString(R.string.str_pair));
		JSONObject info = new JSONObject();
		try {
			info.put(Constants.PARAMETER_USER, user);
			info.put(Constants.PARAMETER_SITE, site);
		} catch (JSONException e) {
			return false;
		}

		return mSiteObj.pairFriends(info);
	}

	private Boolean getFriendsList() {
		JSONObject info = new JSONObject();
		try {
			info.put(Constants.PARAMETER_USER, mUser);
			info.put(Constants.PARAMETER_SITE, mSite);
			info.put(Constants.PARAMETER_PARAMETER, mParameter);
		} catch (JSONException e) {
			return false;
		}

		return mSiteObj.getFriendsList(info);
	}

	private void cleanFriendsList(String user, String site) {
		sendSetDialogMsg(getResources().getString(R.string.str_clean_friends));
		LiteDB.deleteFriendsByAccount(user, site);
		sendSetDialogMsg(getResources().getString(
				R.string.str_clean_relationship));
		LiteDB.deleteRelationshipByAccount(user, site);
	}

	private Boolean updateFriendsList(String user, String site) {
		cleanFriendsList(user, site);
		if (getFriendsList()) {
			return pairFriends(mUser, mSite);
		} else {
			return false;
		}
	}

	private class Downloader extends Thread {
		public void run() {
			this.setName("DownloadThread");
			Looper.prepare();

			mDownloadHandler = new Handler() {
				public void handleMessage(Message msg) {
					switch (msg.what) {
					case DOWNLOAD_START:
						String url = msg.getData().getString("url");
						int position = msg.getData().getInt("position");

						if (LiteDB.get_pic(url) != null) {
							break;
						}

						byte[] pic_data = Common.picDownload(url);
						if (pic_data == null) {
							Log.e("afay", "Download pic fail.");
							break;
						}

						if (LiteDB.put_pic(url, pic_data) < 0) {
							break;
						}

						// Try to tell the main thread: Download complete.
						if (position >= 0) {
							Message sent_msg = new Message();
							sent_msg.what = DOWNLOAD_COMPLETE;
							Bundle b = new Bundle();
							b.putString("url", url);
							b.putInt("position", position);
							sent_msg.setData(b);
							mMainHandler.sendMessage(sent_msg);
						}
						break;
					}

					super.handleMessage(msg);
				}
			};

			Looper.loop();
		}
	}
}
